package org.xlx.xlx_oa.meet.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.xlx.xlx_oa.common.BusinessException;
import org.xlx.xlx_oa.common.Constant;
import org.xlx.xlx_oa.common.PageVo;
import org.xlx.xlx_oa.common.enums.MeetTypeEnums;
import org.xlx.xlx_oa.common.enums.ProcessStatusEnums;
import org.xlx.xlx_oa.common.enums.ProcessTypeEnums;
import org.xlx.xlx_oa.common.enums.YesOrNoEnums;
import org.xlx.xlx_oa.meet.convertor.MeetConvertor;
import org.xlx.xlx_oa.meet.domain.MeetApply;
import org.xlx.xlx_oa.meet.domain.dto.MeetApplyDto;
import org.xlx.xlx_oa.meet.domain.dto.MeetRoomArrangeDto;
import org.xlx.xlx_oa.meet.domain.vo.MeetApplyVo;
import org.xlx.xlx_oa.meet.mapper.MeetApplyMapper;
import org.xlx.xlx_oa.role_user.domain.dto.AdmProcessDto;
import org.xlx.xlx_oa.role_user.domain.vo.AuditVo;
import org.xlx.xlx_oa.role_user.service.AdmProcessService;
import org.xlx.xlx_oa.utils.ThreadLocalUtil;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Service
public class MeetApplyService {
    public static ProcessTypeEnums processType = ProcessTypeEnums.MeetRoom;
    private final MeetConvertor meetConvertor = MeetConvertor.INSTANCE;
    @Autowired
    private MeetApplyMapper meetApplyMapper;
    @Autowired
    private AdmProcessService admProcessService;

    /**
     * 保存会议申请
     *
     * @param applyVo
     * @return
     */
    @Transactional
    public Boolean saveMeetApply(MeetApplyVo applyVo) {
        MeetApply meetApply = meetConvertor.convertVoToMeetApply(applyVo);
        if (meetApply.getId() != null) {
            // update
            MeetApply rowApply = meetApplyMapper.selectById(meetApply.getId());
            if (!ProcessStatusEnums.Pending.name().equals(rowApply.getProcessStatus())) {
                throw new BusinessException("100007", "The application is under review and cannot be modified");
            }
            // if online
            if (MeetTypeEnums.OnLine.name().equals(rowApply.getMeetType())) {
                // if cycle
                if (YesOrNoEnums.Yes.name().equals(rowApply.getIsCycle())) {
                    List<Long> ids = this.getCycleApply(rowApply);
                    meetApplyMapper.deleteBatchIds(ids);
                } else {
                    meetApplyMapper.deleteById(rowApply.getId());
                }
                // if offline
            } else {
                meetApplyMapper.deleteById(rowApply.getId());
            }
        }
        this.insertApply(meetApply);
        boolean flag = meetApply.getMeetUsers().split(",").length > 50;
        Boolean process = admProcessService.createProcess(meetApply.getId(), processType, flag);
        MeetApply temp = meetApplyMapper.selectById(meetApply.getId());
        if (process) {
            temp.setProcessStatus(ProcessStatusEnums.Approve.name());
        } else {
            temp.setProcessStatus(ProcessStatusEnums.Processing.name());
        }
        meetApplyMapper.updateById(temp);
        return true;
    }

    /**
     * 新增会议申请
     *
     * @param meetApply
     */
    public void insertApply(MeetApply meetApply) {
        LocalDateTime startDate
                = LocalDateTime.of(meetApply.getMeetStartDate().toLocalDate(), LocalTime.MIN);
        LocalDateTime endDate
                = LocalDateTime.of(meetApply.getEndTime().toLocalDate(), LocalTime.MIN);
        //insert
        //set process_status
        meetApply.setProcessStatus(ProcessStatusEnums.Pending.name());
        // if online
        if (MeetTypeEnums.OnLine.name().equals(meetApply.getMeetType())) {
            // if cycle
            if (YesOrNoEnums.Yes.name().equals(meetApply.getIsCycle())) {
                // insert cycle time apply
                while (!startDate.isEqual(endDate.plusDays(1))) {
                    MeetApply cycle = meetConvertor.convertToApply(meetApply);
                    cycle.setMeetStartDate(startDate);
                    meetApplyMapper.insert(meetApply);
                    startDate.plusDays(1);
                }
            } else {
                // insert
                meetApplyMapper.insert(meetApply);
            }
            // if offline
        } else {
            //if cycle throw exception
            if (YesOrNoEnums.Yes.name().equals(meetApply.getIsCycle())) {
                throw new BusinessException("100101", "Offline meetings do not support cycle reservation for the time being");
            }
            if (meetApply.getMeetRoomId() == null) {
                throw new BusinessException("100103", "Meeting rooms must be selected for offline meetings");
            }
            // onduty,offduty,flag
            LocalDateTime onDutyTime = startDate.plusHours(9);
            LocalDateTime offDutyTime = startDate.plusHours(18);
            Boolean flag = false;
            //select date all apply
            QueryWrapper<MeetApply> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda()
                    .eq(MeetApply::getMeetRoomId, meetApply.getMeetRoomId())
                    .eq(MeetApply::getMeetStartDate, startDate)
                    .orderByAsc(MeetApply::getStartTime);
            List<MeetApply> meetApplies = meetApplyMapper.selectList(queryWrapper);
            // check meet time correct
            for (int i = 0; i < meetApplies.size(); i++) {
                if (i == 0) {
                    if (onDutyTime.isBefore(meetApply.getStartTime())
                            && meetApplies.get(i).getStartTime().isAfter(meetApply.getEndTime())) {
                        flag = true;
                    }
                    if (meetApplies.size() > 1) {
                        if (meetApplies.get(i).getEndTime().isBefore(meetApply.getStartTime())
                                && meetApplies.get(i + 1).getEndTime().isAfter(meetApply.getEndTime())) {
                            flag = true;
                        }
                    }
                }
                if (meetApplies.get(i).getEndTime().isBefore(meetApply.getStartTime())
                        && meetApplies.get(i + 1).getEndTime().isAfter(meetApply.getEndTime())) {
                    flag = true;
                }
                if (i == meetApplies.size() - 1) {
                    if (meetApplies.get(i).getEndTime().isBefore(meetApply.getStartTime())
                            && offDutyTime.isAfter(meetApply.getEndTime())) {
                        flag = true;
                    }
                }
            }
            // if correct insert
            if (flag) {
                meetApplyMapper.insert(meetApply);
                // if incorrect throw exception
            } else {
                throw new BusinessException("100102", "Offline meeting time overlaps with others");
            }
        }
    }

    /**
     * 审批会议申请
     *
     * @param auditVo
     * @return
     */
    @Transactional
    public Boolean auditMeetApply(AuditVo auditVo) {
        MeetApply meetApply = meetApplyMapper.selectById(auditVo.getApplyId());
        String status = admProcessService.updateAuditProcess(auditVo, meetApply);
        meetApply.setProcessStatus(status);
        return meetApplyMapper.updateById(meetApply) > 0;
    }

    /**
     * 获取待审批考勤申请
     */
    public List<MeetApplyDto> getBeAuditList(PageVo pageVo) {
        Integer pageNum = pageVo.getPageNum();
        Integer pageSize = pageVo.getPageSize();
        Object obj = ThreadLocalUtil.get(Constant.USERID);
        Long userId = Objects.isNull(obj) ? null : Long.valueOf(obj.toString());
        pageNum = (pageNum - 1) * pageSize;
        return meetApplyMapper.selectListAudit(userId, pageNum, pageSize);
    }

    /**
     * 获取审批详情
     *
     * @param applyId
     * @return
     */
    public List<AdmProcessDto> getApplyDetail(Long applyId) {
        List<AdmProcessDto> dtos = meetApplyMapper.selectListProcess(applyId);
        for (AdmProcessDto dto : dtos) {
            ProcessStatusEnums statusEnum
                    = ProcessStatusEnums.valueOf(ProcessStatusEnums.class, dto.getResult());
            dto.setResultName(statusEnum.getText());
        }
        return dtos;
    }

    /**
     * 获取申请列表
     *
     * @param applyVo
     * @return
     */
    public List<MeetApplyDto> getApplyList(MeetApplyVo applyVo) {
        Integer pageNum = applyVo.getPageNum();
        Integer pageSize = applyVo.getPageSize();
        Object obj = ThreadLocalUtil.get(Constant.USERID);
        Long userId = Objects.isNull(obj) ? null : Long.valueOf(obj.toString());
        pageNum = (pageNum - 1) * pageSize;
        List<MeetApplyDto> applyDtos = meetApplyMapper.selectListApply(userId, pageNum, pageSize,
                applyVo.getProcessStatus(), applyVo.getMeetRoomId());
        for (MeetApplyDto applyDto : applyDtos) {
            ProcessStatusEnums statusEnums = ProcessStatusEnums.valueOf(ProcessStatusEnums.class, applyDto.getProcessStatus());
            applyDto.setProcessStatusName(statusEnums.getText());
        }
        return applyDtos;
    }

    /**
     * 获取会议室已预定的安排
     *
     * @param roomId
     * @return
     */
    public List<MeetRoomArrangeDto> getMeetRoomArrange(Long roomId) {
        QueryWrapper<MeetApply> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(MeetApply::getMeetRoomId, roomId)
                .eq(MeetApply::getProcessStatus, ProcessStatusEnums.Approve.name())
                .orderByAsc(MeetApply::getMeetStartDate, MeetApply::getStartTime);
        List<MeetApply> meetApplies = meetApplyMapper.selectList(wrapper);
        return meetConvertor.convertDomainToListArrangeDto(meetApplies);
    }

    /**
     * 判断会议室当前状态
     *
     * @param roomId
     * @return
     */
    public Boolean isBusy(Long roomId) {
        List<MeetRoomArrangeDto> meetRoomArrange = this.getMeetRoomArrange(roomId);
        LocalDateTime now = LocalDateTime.now();
        for (MeetRoomArrangeDto meetRoomArrangeDto : meetRoomArrange) {
            LocalDateTime nowDate = LocalDateTime.of(now.toLocalDate(), LocalTime.MIN);
            if (meetRoomArrangeDto.getMeetStartDate().isEqual(nowDate)) {
                if (meetRoomArrangeDto.getStartTime().isBefore(now)
                        && meetRoomArrangeDto.getEndTime().isAfter(now)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 获取线上循环会议的所有信息
     *
     * @param apply
     * @return
     */
    public List<Long> getCycleApply(MeetApply apply) {
        Object objUserId = ThreadLocalUtil.get(Constant.USERID);
        Long userId = Objects.isNull(objUserId) ? null : Long.valueOf(objUserId.toString());
        QueryWrapper<MeetApply> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(MeetApply::getIsCycle, YesOrNoEnums.Yes.name())
                .eq(MeetApply::getStartTime, apply.getStartTime())
                .eq(MeetApply::getEndTime, apply.getEndTime())
                .eq(MeetApply::getCreatedId, userId);
        List<MeetApply> meetApplies = meetApplyMapper.selectList(wrapper);
        ArrayList<Long> ids = new ArrayList<>();
        for (MeetApply meetApply : meetApplies) {
            ids.add(meetApply.getId());
        }
        return ids;
    }
}
